#include "precompiled.h"
#include "PlaySession.h"

using namespace AudioEngine;

class FacadeStream : public CL_SoundProvider_Session
{
	int pos;
	bool playing;
	sp<Producer const> producer;

public:
	FacadeStream(sp<Producer const> producer)
	{
		this->producer = producer;

		pos = 0;
		playing = false;
	}

	virtual bool eof() const
	{
		return (pos >= get_num_samples());
	}

	virtual void stop()
	{
		playing = false;
	}

	virtual bool play()
	{
		playing = true;
		return true;
	}

	virtual int get_position() const
	{
		return pos;
	}

	virtual bool set_position(int new_pos)
	{
		pos = new_pos;
		return true;
	}

	virtual int get_num_samples() const
	{
		return 60 * get_frequency();
	}

	virtual int get_data(float **data_ptr, int samples_req)
	{
		if (samples_req + pos > get_num_samples())
			// playing beyond the end of stream data
		{
			samples_req = get_num_samples() - pos;
			if (samples_req < 0)
			{
				stop();
				return 0;
			}
		}

		// Generate required audio samples
		for (int i = 0; i < samples_req; i++)
		{
			data_ptr[0][i] = producer->get_sample(pos + i);
			//CL_Console::write_line("%1", data_ptr[0][i]);
		}

		pos += samples_req;

		return samples_req; // return the amount samples given.
	}

	virtual int get_frequency() const
	{
		return Producer::sample_rate;
	}

	virtual CL_SoundFormat get_format() const
	{
		// ClanLib currently doesn't use this, the virtual function will be removed in next ClanLib version.
		return sf_8bit_unsigned;
	}

	virtual int get_num_channels() const
	{
		return 1;
	}
};

class FacadeStreamProvider : public CL_SoundProvider
{
	sp<Producer const> producer;

public:
	FacadeStreamProvider(sp<Producer const> producer)
	{
		this->producer = producer;
	}

	virtual CL_SoundProvider_Session* begin_session()
	{
		return new FacadeStream(producer);
	}

	virtual void end_session(CL_SoundProvider_Session* session)
	{
		delete session;
	}
};

PlaySession::PlaySession(sp<Producer const> producer)
{
	this->producer = producer;
	Producer* p = const_cast<Producer*>(producer.get()); // temp hack
	slot_container.connect(p->sig_finished, this, &PlaySession::stop);

	CL_SoundOutput output(Producer::sample_rate);
	CL_SoundBuffer buffer(new FacadeStreamProvider(producer));
	base_session = CL_SoundBuffer_Session(buffer.prepare());
	base_session.play();
}

PlaySession::~PlaySession()
{
	stop();
}

sp<Producer const> PlaySession::get_producer() const
{
	return producer;
}

void PlaySession::start()
{
	base_session.play();
}

void PlaySession::stop()
{
	base_session.stop();
}
